![]() |
Java Database Programming with JDBC
by Pratik Patel Coriolis, The Coriolis Group ISBN: 1576100561 Pub Date: 10/01/96 |
Previous | Table of Contents | Next |
Because the CommonValue class does not yet support all of the JDBC data types, not all of the set methods have been implemented in the SimpleText driver. You can see, however, how easy it would be to fully implement these methods once CommonValue supported all of the necessary data coercion.
What Is It?
Another way to set parameter values is by using the setObject method. This method can easily be built upon the other set methods. Of interest here is the ability to set an Object without giving the JDBC driver the type of driver being set. The SimpleText driver implements a simple method to determine the type of object, given only the object itself:
protected int getObjectType( Object x) throws SQLException { // Determine the data type of the Object by attempting to cast // the object. An exception will be thrown if an invalid casting // is attempted. try { if ((String) x != null) { return Types.VARCHAR; } } catch (Exception ex) { } try { if ((Integer) x != null) { return Types.INTEGER; } } catch (Exception ex) { } try { if ((byte[]) x != null) { return Types.VARBINARY; } } catch (Exception ex) { } throw new SQLException("Unknown object type"); }
Setting InputStreams
As well see with ResultSet later, using InputStreams is the recommended way to work with long data (blobs). There are two ways to treat InputStreams when using them as input parameters: Read the entire InputStream when the parameter is set and treat it as a large data object, or defer the read until the statement is executed and read it in chunks at a time. The latter approach is the preferred method because the contents of an InputStream may be too large to fit into memory. Heres what the SimpleText driver does with InputStreams:
public void setBinaryStream( int parameterIndex, java.io.InputStream x, int length) throws SQLException { // Validate the parameter index verify(parameterIndex); // Read in the entire InputStream all at once. A more optimal // way of handling this would be to defer the read until execute // time, and only read in chunks at a time. byte b[] = new byte[length]; try { x.read(b); } catch (Exception ex) { throw new SQLException("Unable to read InputStream: " + ex.getMessage()); } // Set the data as a byte array setBytes(parameterIndex, b); }
But wait, this isnt the preferred way! You are correct, it isnt. The SimpleText driver simply reads in the entire InputStream and then sets the parameter as a byte array. Ill leave it up to you to modify the driver to defer the read until execute time.
The ResultSet class provides methods to access data generated by a table query. This includes a series of get methods which retrieve data in any one of the JDBC SQL type formats, either by column number or by column name. When the issue of providing get methods was first introduced by JavaSoft, some disgruntled programmers argued that they were not necessary; if an application wanted to get data in this manner, then the application could provide a routine to cross reference the column name to a column number. Unfortunately (in my opinion), JavaSoft chose to keep these methods in the API and provide the implementation of the cross reference method in an appendix. Because it is part of the API, all drivers must implement the methods. Implementing the methods is not all that difficult, but it is tedious and adds overhead to the driver. The driver simply takes the column name that is given, gets the corresponding column number for the column name, and invokes the same get method using the column number:
public String getString( String columnName) throws SQLException { return getString(findColumn(columnName)); }
And heres the findColumn routine:
public int findColumn( String columnName) throws SQLException { // Make a mapping cache if we don't already have one if (md == null) { md = getMetaData(); s2c = new Hashtable(); } // Look for the mapping in our cache Integer x = (Integer) s2c.get(columnName); if (x != null) { return (x.intValue()); } // OK, we'll have to use metadata for (int i = 1; i < md.getColumnCount(); i++) { if (md.getColumnName(i).equalsIgnoreCase(columnName)) { // Success! Add an entry to the cache s2c.put(columnName, new Integer(i)); return (i); } } throw new SQLException("Column name not found: " + columnName, "S0022"); }
This method uses a Hashtable to cache the column number and column names.
Its Your Way, Right Away
An application can request column data in any one of the supported JDBC data types. As we have discussed before, the driver should coerce the data into the proper format. The SimpleText driver accomplishes this by using a CommonValue object for all data values. Therefore, the data can be served in any format, stored as a CommonValue object, and the application can request it in any other supported format. Lets take a look at the getString method:
public String getString( int columnIndex) throws SQLException { // Verify the column and get the absolute column number for the // table. int colNo = verify(columnIndex); String s = null; if (inMemoryRows != null) { s = (getColumn(rowNum, columnIndex)).getString(); } else { CommonValue value = getValue(colNo); if (value != null) { s = value.getString(); } } if (s == null) { lastNull = true; } return s; }
Previous | Table of Contents | Next |